package com.hp.it.pool.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

public final class ConnectionPool
{
	private ConnectionPool connectionPool = null;
	private int accumulator = 0;

	private static final int POOL_INIT_SIZE = 5;
	private static final int POOL_MAX_SIZE = 80;

	private Queue queuePool;

	private String driverName;
	private String url;
	private String user;
	private String password;

	private Object lock = new Object();

	public ConnectionPool(String driverName, String url, String userName, String password)
			throws ClassNotFoundException, SQLException
	{
		this.driverName = driverName;
		this.url = url;
		this.user = userName;
		this.password = password;
		queuePool = new ConcurrentLinkedQueue();
		initializePool();
	}

	private void initializePool() throws ClassNotFoundException, SQLException
	{
		Connection conn = null;
		try
		{
			Class.forName(driverName);
			for (int i = 0; i < POOL_INIT_SIZE; i++)
			{
				conn = new ConnectionWapper(DriverManager.getConnection(url, user, password), this).getConnection();
				queuePool.add(conn);
				accumulator++;
			}
		} catch (ClassNotFoundException e)
		{
			throw e;
		} catch (SQLException e)
		{
			throw e;
		}
	}

	public Connection getConnection() throws ClassNotFoundException, SQLException
	{
		synchronized (lock)
		{
			Connection conn;
			while (true)
			{
				if (!queuePool.isEmpty())
				{
					conn = (Connection) queuePool.poll();
					if (conn == null || conn.isClosed())
					{
						accumulator--;
						continue;
					}
					return conn;
				} else
				{
					if (accumulator == POOL_MAX_SIZE)
					{
						try
						{
							wait(5000);
						} catch (InterruptedException e)
						{
							e.printStackTrace();
						}
					} else
					{
						// create a new database connection
						try
						{
							Class.forName(driverName);
							conn = new ConnectionWapper(DriverManager.getConnection(url, user, password), this)
									.getConnection();
							accumulator++;
							return conn;
						} catch (ClassNotFoundException e)
						{
							throw e;
						} catch (SQLException e)
						{
							throw e;
						}
					}
				}
			}
		}
	}

	public synchronized boolean releaseConnection(Connection conn)
	{
		if (queuePool.size() < POOL_MAX_SIZE)
		{
			synchronized (lock)
			{
				queuePool.add(conn);
				notify();
				return true;
			}
		}
		return false;
	}

	public static void main(String[] args) throws Exception
	{
		ConnectionPool cp = new ConnectionPool("com.mysql.jdbc.Driver", "jdbc:mysql://127.0.0.1:3306/sonar", "sonar",
				"sonar");
		Connection conn = cp.getConnection();
		Connection conn2 = cp.getConnection();
		System.out.println(conn);
		conn.close();
		Connection conn3 = cp.getConnection();
		Connection conn4 = cp.getConnection();
		Connection conn5 = cp.getConnection();
		Connection conn6 = cp.getConnection();

		System.out.println(conn2);
		System.out.println(conn3);
		System.out.println(conn4);
		System.out.println(conn5);
		System.out.println(conn6);

		conn.close();
	}
}